/*
 * Copyright 2024 The JA-SIG Collaborative. All rights reserved.
 * distributed with thi file and available online at
 */
package com.lap.permission.api;

import com.lap.framework.builder.resource.DefaultBuilder;
import com.lap.framework.builder.resource.ResourceDirector;
import com.lap.framework.dto.resource.ClassDTO;
import com.lap.framework.enums.YesNo;
import com.lap.framework.spring.holder.SpringHolder;
import com.lap.framework.validator.Update;
import com.lap.framework.watchdog.annotation.Repeat;
import com.lap.permission.convert.Convert;
import com.lap.permission.domain.entity.Resource;
import com.lap.permission.dto.request.ResourceRemoteRequest;
import com.lap.permission.dto.request.ResourceRequest;
import com.lap.permission.dto.request.ResourceUploadRequest;
import com.lap.permission.service.ResourceService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * <pre>
 *  资源 Controller,控制业务流程。
 *  提供包括业务流程校验,业务流程控制。当流程非常复杂时候,请在API和Service之间添加一层Manager。
 *  Controller 对外开放Rest,同时可以做简单流程控制。Manager复杂流程控制。Service数据完整性(事务)。DAO/Mapper持久操作。
 *  流程简单: Controller->Service->DAO
 *  复杂流程: Controller->Manager->Service->DAO
 *  对外流程: Controller->Manager->Service->DAO
 * 					    |->外部服务
 *  <b>uri 规则</b>
 *   uri 名词复数.
 *   列表或分页 : GET /persons
 *   单人信息   : GET /persons/1
 *   新增      : POST /persons
 *   修改      : PUT /persons
 *   删除      : DELETE /persons/1
 * </pre>
 *
 * @author Shuisheng Lao(劳水生)
 * @version 0.0.1
 * @see ResourceService
 * @see ResourceRequest
 * @see Resource
 */
@Tag(name = "资源")
@RequiredArgsConstructor
@RestController
@RequestMapping("api/resources")
public class ResourceController {

    private final ResourceService resourceService;

    private final Convert convert;

    @Operation(summary = "资源列表")
    @GetMapping
    public List<Resource> queryTree() {
        return resourceService.queryTree();
    }

    @Operation(summary = "资源用户获取")
    @GetMapping("user/{userId}")
    public List<Resource> queryByUserId(@PathVariable Integer userId) {
        return resourceService.queryByUserId(userId);
    }

    @Operation(summary = "资源服务类型获取")
    @GetMapping("service/{type}")
    public List<Resource> queryByService(@PathVariable Integer type) {
        return resourceService.queryByService(type);
    }

    @Operation(summary = "资源菜单ID获取")
    @GetMapping("menu/{menuId}")
    public List<Resource> queryByMenuId(@PathVariable Integer menuId) {
        return resourceService.queryByMenuId(menuId);
    }

    @Operation(summary = "资源远程上报")
    @Repeat
    @PostMapping("upload/remote")
    public Integer uploadResource(@RequestBody ResourceRemoteRequest request) {
        List<Resource> data = getResources(request.getModule(), request.getServiceFlag(), request.getResources());
        return resourceService.insertResourceBatch(request.getModule(), data);
    }

    @Operation(summary = "资源上报")
    @Repeat
    @PostMapping("upload")
    public Integer uploadResource(@RequestBody ResourceUploadRequest request) {
        List<Object> sourceList = SpringHolder.getBeansWithAnnotation(RestController.class);
        ResourceDirector director = new ResourceDirector(new DefaultBuilder());
        List<ClassDTO> classList = director.construct(request.getModule(), request.getName(), sourceList);
        List<Resource> dataList = getResources(request.getModule(), request.getServiceFlag(), classList);

        return resourceService.insertResourceBatch(request.getModule(), dataList);
    }

    private List<Resource> getResources(String module, Integer serviceFlag, List<ClassDTO> classList) {
        if (CollectionUtils.isEmpty(classList)) {
            return Collections.emptyList();
        }
        List<Resource> query = resourceService.queryByModule(module);
        return classList.stream().map(item -> getResource(serviceFlag, query, item)).toList();
    }

    private Resource getResource(Integer serviceFlag, List<Resource> query, ClassDTO dto) {
        Resource resource = convert.toResource(dto);
        Resource update = getUpdate(resource, query);
        if (Objects.nonNull(update)) {
            resource.setFunctionFlag(update.getFunctionFlag());
            resource.setDataFlag(update.getDataFlag());
            resource.setDesensitizeFlag(update.getDesensitizeFlag());
            resource.setDesensitizeJson(update.getDesensitizeJson());
            resource.setServiceFlag(update.getServiceFlag());
            resource.setUpdateFlag(update.getUpdateFlag());
        } else {
            setDefaultValues(resource, serviceFlag);
        }
        return resource;
    }

    private void setDefaultValues(@NonNull Resource resource, Integer serviceFlag) {
        resource.setFunctionFlag(YesNo.YES.getValue());
        resource.setDataFlag(YesNo.NO.getValue());
        resource.setDesensitizeFlag(YesNo.NO.getValue());
        resource.setServiceFlag(serviceFlag);
        resource.setUpdateFlag(YesNo.NO.getValue());
    }

    private Resource getUpdate(Resource resource, List<Resource> query) {
        return query.stream()
                .filter(item -> StringUtils.isNotBlank(item.getCode()))
                .filter(item -> item.getCode().equals(resource.getCode()))
                .findFirst()
                .orElse(null);
    }

    @Operation(summary = "资源更新")
    @PutMapping
    public Integer updateResource(@RequestBody @Validated(Update.class) ResourceRequest request) {
        Resource resource = convert.toResource(request);
        resource.setUpdateFlag(YesNo.YES.getValue());
        return resourceService.updateResource(resource);
    }

}
